(function () {
  var vm = {};
  class Vue {
    constructor(options) {
      this._init(options)
    }

    // 静态属性,属于Vue类,而不是实例
    static name = 'Vue';
    static version = '1.0.0';

    _init(options) {
      vm = this;
      vm.$options = options;
      initState();
      vm.$mount();
    }

    $mount() {
      var el = document.querySelector(this.$options.el);
      var dom = document.createElement(this.$options.render.tag);
      var text = document.createTextNode(this.$options.render.text);
      dom.appendChild(text);
      el.appendChild(dom);
      new Watcher(vm, 'id', (val) => {
        dom.innerText = val
      })
    }

    // 相当于在constructor定义computed方法
    // get id () {
    //     return '1'
    // }
    $watch(expOrFn, cb) {
      new Watcher(this, expOrFn, cb)
    }
  }

  class Dep {
    constructor() {
      this.subs = [];
    }

    static target = null;
    // addSub (sub) {
    //     this.subs.push(sub);
    // }
    removeSub(sub) {
      remove(this.subs, sub);
    }

    depend(sub) {
      this.subs.push(sub);
    }

    notify() {
      var subs = this.subs;
      for (var i = 0, l = subs.length; i < l; i++) {
        subs[i].update();
      }
    }
  }

  class Observer {
    constructor() {
      this.value = vm.$data;
      this.walk();
    }

    walk() {
      var dep = new Dep();
      let handler = {
        get(target, name) {
          if (Dep.target) {
            dep.depend(Dep.target)
          }
          console.log('get')
          return target[name]
        },
        set(obj, prop, value) {
          if (obj[prop] !== value) {
            obj[prop] = value;
            dep.notify();
          }
        }
      };
      vm._data = new Proxy(vm.$data, handler);
    }
  }

  class Watcher {
    // vm是实例,expOrFn是'$route.path'这样的表达式,cb是处理函数
    constructor(vm, expOrFn, cb) {
      this.vm = vm;
      this.expOrFn = expOrFn;
      this.cb = cb;
      this.value = this.get();
    }

    get() {
      // 判断它是Watcher的this.get调用的，而不是普通调用
      Dep.target = this;
      var value = this.vm._data[this.expOrFn];
      Dep.target = null;
      return value
    }

    run() {
      var value = this.vm._data[this.expOrFn];
      var oldValue = this.value;
      this.cb.call(this.vm, value, oldValue);
    }

    update() {
      this.run()
    }
  }

  function remove(arr, item) {
    if (arr.length) {
      var index = arr.indexOf(item);
      if (index > -1) {
        return arr.splice(index, 1)
      }
    }
  }

  function initState() {
    if (vm.$options.data) {
      initData();
    }
  }

  function initData() {
    var data = vm.$options.data;
    typeof data === 'function' && (vm.$data = data())
    new Observer();
  }

  window.Vue = Vue;
})();
